<!--
author:        hejy <silentmanager@163.com>
date:          2024-11-01 13:50:59
component:     index
Copyright © YourCompanyName All rights reserved
-->
<script lang="ts">
import { defineComponent, ref, defineExpose } from 'vue'
import {
  ElForm,
  ElInput,
  ElInputNumber,
  ElSelect,
  ElDatePicker,
  ElCheckbox,
  ElRadioGroup,
  ElTreeSelect
} from 'element-plus'

interface FieldConfig {
  label: string
  prop: string
  type: string
  options?: any // 组件特定配置
  itemProps?: any
  span?: number
}

export default defineComponent({
  name: 'FormComponent',
  props: {
    config: {
      type: Array as () => FieldConfig[],
      required: true
    },
    initialValues: {
      type: Object,
      default: () => ({})
    },
    rules: {
      type: Object,
      default: () => ({})
    },
    extraProps: {
      type: Object,
      default: () => ({})
    },
    useGrid: {
      type: Boolean,
      default: false
    }
  },
  setup(props, { emit }) {
    const formRef = ref<InstanceType<typeof ElForm> | null>(null)
    const formData = ref({ ...props.initialValues })
    const formRules = ref(props.rules)

    // 根据字段类型返回组件
    const getComponentType = (field: FieldConfig) => {
      if (field.type === 'select' || field.type === 'radio') {
        return
      }
      const componentMap: Record<string, any> = {
        input: ElInput,
        number: ElInputNumber,
        select: ElSelect,
        date: ElDatePicker,
        checkbox: ElCheckbox,
        radio: ElRadioGroup,
        tree: ElTreeSelect
      }
      return componentMap[field.type] || ElInput
    }

    // 提交表单
    const handleSubmit = () => {
      formRef.value?.validate((valid) => {
        if (valid) {
          emit('submit', formData.value)
        }
      })
    }

    // 重置表单
    const handleReset = () => {
      formRef.value?.resetFields()
    }
    const setData = (data) => {
      formData.value = data
    }
    const setSingleData = (key: string, value: any) => {
      formData.value[key] = value
    }
    defineExpose({
      formData,
      handleReset,
      setData,
      setSingleData,
      formRef
    })
    watch(
      () => props.initialValues,
      (newValues) => {
        formData.value = { ...newValues }
      }
    )
    return {
      formRef,
      formData,
      formRules,
      getComponentType,
      handleSubmit,
      handleReset,
      props,
      setData,
      setSingleData
    }
  }
})
</script>

<template>
  <el-form
    v-bind="extraProps"
    :inline="!props.useGrid"
    :model="formData"
    :rules="formRules"
    ref="formRef"
    label-width="100px"
  >
    <el-row v-if="props.useGrid" :gutter="20">
      <el-col :span="field.span || 12" v-for="field in config" :key="field.prop">
        <el-form-item
          v-bind="field.itemProps"
          :key="field.prop"
          :label="field.label"
          :prop="field.prop"
        >
          <template v-if="field.type === 'select'">
            <el-select v-model="formData[field.prop]" v-bind="field.options">
              <el-option
                v-for="option in field.options.options"
                :key="option.value"
                :label="option.label"
                :value="option.value"
              />
            </el-select>
          </template>
          <template v-if="field.type === 'radio'">
            <el-radio-group v-model="formData[field.prop]" v-bind="field.options">
              <el-radio
                v-for="option in field.options.options"
                :key="option.value"
                :label="option.value"
              >
                {{ option.label }}
              </el-radio>
            </el-radio-group>
          </template>
          <template v-else>
            <component
              :is="getComponentType(field)"
              v-model="formData[field.prop]"
              v-bind="field.options"
            />
          </template>
        </el-form-item>
      </el-col>
    </el-row>
    <el-row v-if="!props.useGrid">
      <el-form-item
        v-for="field in config"
        v-bind="field.itemProps"
        :key="field.prop"
        :label="field.label"
        :prop="field.prop"
      >
        <template v-if="field.type === 'select'">
          <el-select v-model="formData[field.prop]" v-bind="field.options">
            <el-option
              v-for="option in field.options.options"
              :key="option.value"
              :label="option.label"
              :value="option.value"
            />
          </el-select>
        </template>
        <template v-if="field.type === 'radio'">
          <el-radio-group v-model="formData[field.prop]" v-bind="field.options">
            <el-radio
              v-for="option in field.options.options"
              :key="option.value"
              :label="option.value"
            >
              {{ option.label }}
            </el-radio>
          </el-radio-group>
        </template>
        <template v-else>
          <component
            :is="getComponentType(field)"
            v-model="formData[field.prop]"
            v-bind="field.options"
          />
        </template>
      </el-form-item>
    </el-row>

    <!-- 自定义提交按钮插槽 -->
    <el-form-item>
      <slot name="submit"> </slot>
    </el-form-item>
  </el-form>
</template>
